import math
import csv


def euclidean_distance(point1, point2):
    return math.sqrt(sum((x - y) ** 2 for x, y in zip(point1, point2)))

def get_neighbors(training_data, test_point, k):
    distances = []
    for train_point, label in training_data:
        dist = euclidean_distance(test_point, train_point)
        distances.append((dist, label))

    distances.sort(key=lambda x: x[0])

    neighbors = [label for _, label in distances[:k]]
    return neighbors

def vote(neighbors):
    return max(set(neighbors), key=neighbors.count)

def knn(training_data, test_data, k):
    predictions = []
    for test_point in test_data:
        neighbors = get_neighbors(training_data, test_point[:-1], k)  # test_point[:-1]是去掉标签的特征部分
        prediction = vote(neighbors)
        predictions.append(prediction)
    return predictions



def load_iris_data(file_path):
    data = []
    with open(file_path, 'r') as file:
        reader = csv.reader(file)
        for row in reader:
            if len(row) < 5:  # 确保行包含足够的数据（4个特征 + 1个标签）
                continue
            features = list(map(float, row[:-1]))  # 提取特征，转换为浮动类型
            label = row[-1]  # 类别标签
            data.append((features, label))
    return data

def train_test_split(data, test_size=0.2):
    from random import shuffle
    shuffle(data)
    test_length = int(len(data) * test_size)
    return data[test_length:], data[:test_length]

def main():
    training_file_path = "iris.data"
    data = load_iris_data(training_file_path)

    test_data, train_data = train_test_split(data, test_size=0.2)

    k = 3
    test_features = [sample[0] for sample in test_data]
    predictions = knn(train_data, test_features, k)

    for i, (sample, prediction) in enumerate(zip(test_data, predictions)):
        true_label = sample[-1]
        print(f"测试样本 {i + 1}: 实际标签 = {true_label}, 预测标签 = {prediction}")

    correct = sum(1 for i, sample in enumerate(test_data) if sample[-1] == predictions[i])
    accuracy = correct / len(test_data)
    print(f"准确率为: {accuracy * 100:.2f}%")


# 执行主程序
if __name__ == "__main__":
    main()
